package com.demo.java.redis.lock;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static com.demo.java.redis.RedissonClientTest.createSingleClient;

/**
 * 读 + 读 ：相当于无锁，并发读，只会在redis中记录好，所有当前的读锁，他们都会同时加锁成功。
 * 写 + 读 ：等待写锁释放。
 * 写 + 写：阻塞方式
 * 读 + 写：有读锁，写也需要等待
 * 只要有写的存在，都必须等待
 */
@Slf4j
public class RedissonReadWriteLockTest {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(2);
        // 读线程
        Thread readThread = new Thread(() -> {
//            try {
//                // 停一会让写线程先获取写锁
//                log.info("读线程将要歇一会让写线程先执行");
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            RedissonClient client = createSingleClient();
            RReadWriteLock rwLock = client.getReadWriteLock("rwlocktest");
            RLock rlock = rwLock.readLock();
            log.info("读线程将要获取读锁");
            rlock.lock(120, TimeUnit.SECONDS);
            log.info("读线程获取到读锁");

            try {
                log.info("读线程执行业务开始");
                // 读线程执行5秒
                log.info("读线程执行业务结束");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            log.info("读线程将要释放读锁");
            rlock.unlock();
            log.info("读线程释放读锁结束");
            client.shutdown();
            latch.countDown();
        }, "read-lock");

        // 写线程
        Thread writeThread = new Thread(() -> {
            RedissonClient client = createSingleClient();
            RReadWriteLock rwLock = client.getReadWriteLock("rwlocktest");
            RLock wlock = rwLock.writeLock();
            log.info("写线程将要获取写锁");
            wlock.lock(120, TimeUnit.SECONDS);
            log.info("写线程获取到写锁");

            try {
                log.info("写线程执行业务开始");
                // 写线程执行5秒
                Thread.sleep(5000);
                log.info("写线程执行业务结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("写线程将要释放写锁");
            wlock.unlock();
            log.info("写线程释放写锁结束");
            client.shutdown();
            latch.countDown();
        }, "write-lock");

        writeThread.start();
        Thread.sleep(100);
        readThread.start();

        latch.await();
        Thread.sleep(30000);
    }
}
